package com.googlecode.gwtptk.client;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.*;

/**
 * Simple abstract page control widget for moving between pages. It is meant to be subclassed
 * in order to implement {@link #onChange()} method.
 *
 * @author <a href="mailto:richard.richter@siemens-enterprise.com">Richard "Virgo" Richter</a>
 */
public abstract class PageControls extends SimplePanel {
	private Label firstBtn;
	private Label previous100Btn;
	private Label previous10Btn;
	private Label previousBtn;
	private Label nextBtn;
	private Label next10Btn;
	private Label next100Btn;
	private Label lastBtn;
	private Label pageLabel = new Label();
	HorizontalPanel buttons = new HorizontalPanel();

	// valid only from update to update
	private PageOf<?> page;

	/**
	 * Creates new paging controls.
	 */
	public PageControls() {
		firstBtn = new Label("||<");
		firstBtn.addStyleName("pagecontrol-link");
		firstBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				first();
			}
		});
		previous100Btn = new Label("100<");
		previous100Btn.addStyleName("pagecontrol-link");
		previous100Btn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				addPage(-100);
			}
		});
		previous10Btn = new Label("10<");
		previous10Btn.addStyleName("pagecontrol-link");
		previous10Btn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				addPage(-10);
			}
		});
		previousBtn = new Label("1<");
		previousBtn.addStyleName("pagecontrol-link");
		previousBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				addPage(-1);
			}
		});
		nextBtn = new Label(">1");
		nextBtn.addStyleName("pagecontrol-link");
		nextBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				addPage(1);
			}
		});
		next10Btn = new Label(">10");
		next10Btn.addStyleName("pagecontrol-link");
		next10Btn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				addPage(10);
			}
		});
		next100Btn = new Label(">100");
		next100Btn.addStyleName("pagecontrol-link");
		next100Btn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				addPage(100);
			}
		});
		lastBtn = new Label(">||");
		lastBtn.addStyleName("pagecontrol-link");
		lastBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent clickEvent) {
				last();
			}
		});
		buttons.addStyleName("table-controls-flow-grid");
		buttons.setSpacing(3);
		this.add(buttons);
		this.addStyleName("table-controls");
	}

	private void first() {
		if (page == null) {
			Window.alert(nullPageWarning());
			return;
		}
		page.goToFirstPage();
		onChange();
	}

	private void addPage(int pageChange) {
		if (page == null) {
			Window.alert(nullPageWarning());
			return;
		}
		page.addPage(pageChange);
		onChange();
	}

	private void last() {
		if (page == null) {
			Window.alert(nullPageWarning());
			return;
		}
		page.goToLastPage();
		onChange();
	}

	public abstract void onChange();

	/**
	 * Must be called after the page is retrieved to refresh visuals of this control widget.
	 * Must be called after every change of page. It is not called from internal page change
	 * handlers, because client programmer has to provide fresh version of the page object.
	 *
	 * @param ppage fresh Page Of object
	 */
	public void update(PageOf<?> ppage) {
		this.page = ppage;
		buttons.clear();
		if (page.hasPrevious()) {
			buttons.add(firstBtn);
			if (page.totalPages() > 150) {
				buttons.add(previous100Btn);
			}
			if (page.totalPages() > 15) {
				buttons.add(previous10Btn);
			}
			buttons.add(previousBtn);
		}
		pageLabel.setText(pageXOfYLabel(page.currentPage(), page.totalPages()));
		pageLabel.addStyleName("pagecontrol");
		buttons.add(pageLabel);
		if (page.hasNext()) {
			buttons.add(nextBtn);
			if (page.totalPages() > 15) {
				buttons.add(next10Btn);
			}
			if (page.totalPages() > 150) {
				buttons.add(next100Btn);
			}
			buttons.add(lastBtn);
		}
	}

	/**
	 * Override this method to get customized "page x/y" message.
	 *
	 * @param x current page
	 * @param y total pages
	 * @return string "page x/y"
	 */
	protected String pageXOfYLabel(int x, int y) {
		return "Page " + x + "/" + y;
	}

	protected String nullPageWarning() {
		return "UI page is null in page control updates";
	}
}
